﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TaskBarInfo
{
    public partial class FrmTaskBar : Form
    {
        private PerformanceCounterCategory categoryNet = null;
        private List<PerformanceCounter> listNetRecv = null;
        private List<PerformanceCounter> listNetSent = null;
        private PerformanceCounter counterCpu = null;
        private ManagementClass mc;

        private readonly string CategoryNameNet = @"Network Interface";
        private readonly string ConuterNameNetRecv = @"Bytes Received/sec";
        private readonly string ConuterNameNetSent = @"Bytes Sent/sec";
        private readonly string CategoryNameCpu = @"Processor";
        private readonly string ConuterNameCpu = @"% Processor Time";
        private readonly string InstanceNameCpu = @"_Total";


        private Timer timer;
        private int indexTimer = 0;

        private InfoMode infoMode;

        public FrmTaskBar()
        {
            InitializeComponent();

            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
            SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            /*
            PerformanceCounterCategory processcounter = new PerformanceCounterCategory("Memory");
            string[] instances = processcounter.GetInstanceNames();
            foreach (string instance in instances)
            {
                //PerformanceCounter counter = new PerformanceCounter("Processor", "% Processor Time", instance);
                Console.WriteLine(instance);
            }
            */
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams paras = base.CreateParams;
                paras.ExStyle |= 0x02000000;
                return paras;
            }
        }

        private void FrmTaskBar_Load(object sender, EventArgs e)
        {
            infoMode = InfoMode.NetSpeed;
            pnlCpuMem.Visible = false;
            // 网速
            categoryNet = new PerformanceCounterCategory(CategoryNameNet);
            listNetRecv = new List<PerformanceCounter>();
            listNetSent = new List<PerformanceCounter>();

            var instanceNames = categoryNet.GetInstanceNames();
            if (instanceNames.Length == 0)
            {
                MessageBox.Show(@"不存在网卡！");
                Close();
            }

            foreach (string instanceName in instanceNames)
            {
                listNetRecv.Add(new PerformanceCounter(CategoryNameNet, ConuterNameNetRecv, instanceName));
                listNetSent.Add(new PerformanceCounter(CategoryNameNet, ConuterNameNetSent, instanceName));
            }
            // CPU 和 内存
            counterCpu = new PerformanceCounter(CategoryNameCpu, ConuterNameCpu, InstanceNameCpu);
            mc = new ManagementClass("Win32_OperatingSystem");
            // 启动定时器
            timer = new Timer {Interval = 100};
            timer.Tick += Timer_Tick;
            timer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (indexTimer % 5 == 0)
            {
                ReLocateForm();
            }

            if (indexTimer % 20 == 0)
            {
                switch (infoMode)
                {
                    case InfoMode.NetSpeed:
                        lblUp.Text = GetNetSpeedStr(GetBytesNetSpeedSent());
                        lblDown.Text = GetNetSpeedStr(GetBytesNetSpeedRecv());
                        break;
                    case InfoMode.CpuMem:
                        lblCpu.Text = GetCpuStr();
                        lblMemory.Text = GetMemoryStr();
                        break;
                    default:
                        break;
                }
            }

            this.TopMost = true;

            indexTimer++;
            if (indexTimer > 19) indexTimer = 0;
        }

        private float GetBytesNetSpeedRecv()
        {
            return listNetRecv.Sum(counter => counter.NextValue());
        }

        private float GetBytesNetSpeedSent()
        {
            return listNetRecv.Sum(counter => counter.NextValue());
        }

        private string GetNetSpeedStr(float numBytes)
        {
            const int mb = 1024 * 1024;
            if (numBytes < 1024)
            {
                return numBytes.ToString("0.00") + "B/S";
            }
            else if (numBytes >= 1024 && numBytes < mb)
            {
                return (numBytes / 1024).ToString("0.00") + "KB/S";
            }
            return ((numBytes / mb).ToString("0.00") + "MB/S").PadLeft(10, ' ');
        }

        private string GetCpuStr()
        {
            if (counterCpu == null) return string.Empty;

            return (counterCpu.NextValue().ToString("0.00") + "%").PadLeft(10, ' ');
        }

        private string GetMemoryStr()
        {
            if (mc == null) return string.Empty;

            long totalMem = 0, availMem = 0;
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject mo in moc)
            {
                if (mo["TotalVisibleMemorySize"] != null)
                {
                    totalMem = long.Parse(mo["TotalVisibleMemorySize"].ToString());
                }

                if (mo["FreePhysicalMemory"] != null)
                {
                    availMem = long.Parse(mo["FreePhysicalMemory"].ToString());
                }
            }

            double percent = (1 - availMem * 1.0 / totalMem) * 100;
            return (percent.ToString("0.00") + "%").PadLeft(10, ' ');
        }

        private Rectangle GetNotifyWndRect()
        {
            IntPtr handle = WinApi.FindWindow("Shell_TrayWnd", null);
            handle = WinApi.FindWindowEx(handle, IntPtr.Zero, "TrayNotifyWnd", null);

            WinApi.RECT rc = new WinApi.RECT();
            WinApi.GetWindowRect(handle, ref rc);

            Rectangle rect = new Rectangle(rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top);
            return rect;
        }

        private void ReLocateForm()
        {
            Rectangle rectNotifyWnd = GetNotifyWndRect();

            if (rectNotifyWnd.Height < this.Height)
            {
                this.Height = rectNotifyWnd.Height;
                pnlNetSpeed.Height = this.Height;
                pnlCpuMem.Height = this.Height;
                pnlImgUp.Width = this.Height;
                pnlImgUp.Height = this.Height;
                pnlImgDown.Width = this.Height;
                pnlImgDown.Height = this.Height;
                pnlImgCpu.Width = this.Height;
                pnlImgCpu.Height = this.Height;
                pnlImgMemory.Width = this.Height;
                pnlImgMemory.Height = this.Height;
                if (this.Height < 30)
                {
                    Font font = new Font("Arial", 10);
                    lblUp.Font = font;
                    lblUp.Font = font;
                    lblCpu.Font = font;
                    lblMemory.Font = font;
                }
                else if (this.Height < 46)
                {
                    Font font = new Font("Arial", 15);
                    lblUp.Font = font;
                    lblUp.Font = font;
                    lblCpu.Font = font;
                    lblMemory.Font = font;
                }
                else
                {
                    Font font = new Font("Arial", 18);
                    lblUp.Font = font;
                    lblUp.Font = font;
                    lblCpu.Font = font;
                    lblMemory.Font = font;
                }
            }

            Size screenSize = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Point location = new Point
            {
                X = screenSize.Width - rectNotifyWnd.Width - this.Width,
                Y = screenSize.Height - this.Height - (rectNotifyWnd.Height - this.Height) / 2
            };
            this.Location = location;
        }

        private void FrmTaskBar_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (timer != null)
            {
                timer.Stop();
                timer.Dispose();
                timer = null;
            }

            if (listNetRecv != null)
            {
                foreach (PerformanceCounter counter in listNetRecv)
                {
                    counter.Dispose();
                }
                listNetRecv.Clear();
                listNetRecv = null;
            }

            if (counterCpu != null)
            {
                counterCpu.Dispose();
                counterCpu = null;
            }

            if (listNetSent != null)
            {
                foreach (PerformanceCounter counter in listNetSent)
                {
                    counter.Dispose();
                }
                listNetSent.Clear();
                listNetSent = null;
            }
        }

        private void menuItemExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void FormMouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                menuStrip.Show(this.PointToScreen(e.Location));
            }
        }

        private void menuItemNet_Click(object sender, EventArgs e)
        {
            pnlCpuMem.Visible = false;
            pnlNetSpeed.Visible = true;
            infoMode = InfoMode.NetSpeed;
        }

        private void menuItemCpuMem_Click(object sender, EventArgs e)
        {
            pnlNetSpeed.Visible = false;
            pnlCpuMem.Visible = true;
            infoMode = InfoMode.CpuMem;
        }
    }


    internal enum InfoMode
    {
        NetSpeed = 0,
        CpuMem = 1
    }
}
